#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>   /* printk() */
#include <linux/cdev.h> /* cdev... */
#include <linux/fs.h>       /* everything... */
#include <linux/types.h>    /* size_t */
#include <linux/uaccess.h>
#include <linux/kdev_t.h>



#define DEVICE_NUMBER 1 //需要注册设备的数量

#define DEVICE_SNAME "s_my_cdev" //动态分配的设备名称
#define DEVICE_ANAME "a_my_cdev" //静态分配的设备名称

#define DEVICE_MINOR_NUMBER 0
#define DEVICE_CLASS_NAME "my_cdev_class"//类的名称
#define DEVICE_NODE_NAME "my_cdev_nod" //要生成的设备节点的名称


static int major_num,minor_num;


module_param(major_num,int,S_IRUSR);//驱动传参，不了解的搜一下，比较简单
module_param(minor_num,int,S_IRUSR);


int cedv_open(struct inode *inode,struct file *file)
{
    printk( "open cedv\n");
    return 0;
}

struct file_operations cedv_fops={
  .owner   = THIS_MODULE,
  .open    = cedv_open,
};

dev_t dev_num;//设备号

struct cdev cdev ;       //字符设备结构体
struct class *class ;  //类相关的结构体
struct device *device ;  //设备节点相关的结构体

static int cdevice_init(void)
{


    int ret;


    if(major_num)//输入参数了就静态分配，没有就动态分配
    {

        printk( "major_num = %d \n",major_num);
        printk( "minor_num = %d \n",minor_num);

        dev_num = MKDEV(major_num,minor_num);

        ret=register_chrdev_region(dev_num, DEVICE_NUMBER, DEVICE_SNAME);
        if(ret < 0)
        {
            printk( "register_chrdev_region is failed\n");

            return -1;
        }
        printk( "register_chrdev_region is succeed\n");

    }
    else
    {
        ret =alloc_chrdev_region(&dev_num,DEVICE_MINOR_NUMBER, DEVICE_NUMBER, DEVICE_ANAME);
        if(ret < 0)
        {
            printk( "alloc_chrdev_region is failed\n");

            return -1;
        }
        printk( "alloc_chrdev_region is succeed\n");

        major_num = MAJOR(dev_num);
        minor_num = MINOR(dev_num);

        printk( "major_num = %d \n",major_num);
        printk( "minor_num = %d \n",minor_num);

    }

    /******************上边的是分配设备号****************************/
    cdev.owner = THIS_MODULE;

    cdev_init(&cdev ,&cedv_fops);

    cdev_add(&cdev, dev_num, DEVICE_NUMBER);

    /******************上边的是注册字符设备**************************/

    class = class_create(THIS_MODULE,DEVICE_CLASS_NAME);

    device = device_create(class,NULL,dev_num,NULL,DEVICE_NODE_NAME);
    /******************上边的是自动生成设备节点**********************/



    return 0;

}
static void cedvice_exit(void)
{
    unregister_chrdev_region(MKDEV(major_num,minor_num), DEVICE_NUMBER);
    cdev_del(&cdev);
    device_destroy(class, dev_num);
    class_destroy(class);

    printk(KERN_ALERT "Goodbye,cdev\n");
}

/* register the init and exit routine of the module */
module_init( cdevice_init );
module_exit( cedvice_exit );

MODULE_LICENSE("GPL");
